#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const exec = require('child_process').exec;
const OptionParser = require('brisket/lib/optparse');
const {fgets, getVersion, awk, pad, ensureFileExists} = require('./utils.js');

const file_name = __dirname + '/unihan/Unihan_Readings.txt';
const out_file = __dirname + '/../chrome/unicode/fftt_han_ja.dat';

const data = [];
var version;
var runmode = {};

function setup () {
	var count = 0;
	var bits = [];

	for (var i = 65; i <= 90; i++) {
		bits[i] = 0;
	}

	fgets(file_name, line => {
		line = line.split('\t');
		if (line.length != 3) return;
		if (line[1] != 'kJapaneseOn' && line[1] != 'kJapaneseKun') return;
		if (line[0].length != 6) return true;

		var code_point = parseInt(line[0].substring(2, 6), 16);
		if (data[code_point] == undefined) {
			data[code_point] = 0;
		}

		line[2].split(' ').some(r => {
			r = r.charCodeAt(0);
			if (r < 65 || r > 90) {
				console.log(`\n*** invalid code point: ${line.join('\t')}`);
				return true;
			}

			data[code_point] |= 1 << (r - 65);
			bits[r]++;
		});

		count++;
		if (count % 100 == 0) {
			process.stdout.write(`\r${count}`);
		}
	});
}

function make_dict () {
	var packmap = {};
	var bits = 0;
	var codes = [];

	for (var i = 0; i < 26; i++) {
		packmap[`${i}_`] = i;
	}

	data.forEach((d, cp) => {
		bits |= d;
	});

	for (var i = 0, mask = 1; i < 26; i++, mask <<= 1) {
		if (!(bits & mask)) {
			delete packmap[`${i}_`];
			codes.push(`\t//omitted: '${String.fromCharCode(97 + i)}'`);
		}
	}

	if (Math.floor((packmap.length + 7) / 8) > 3) {
		throw new Error('data size too large.');
	}
	
	var mask = 1;
	for (var k in packmap) {
		packmap[k] = mask;
		mask <<= 1;
	}

	/* javascript code */

	if (runmode.packmap) {
		var delimiter = ' ';
		for (var k in packmap) {
			var v = packmap[k];
			codes.push(`\t${delimiter}0x${pad(v, '0', 6)}: '${String.fromCharCode(97 + parseInt(k, 10))}'`);
			delimiter = ',';
		}
		codes.sort((a, b) => a.substr(-2).localeCompare(b.substr(-2)));

		console.log(`\r// packmap info derived from Unicode ${version}`);
		console.log(`// generated by "src/unicode-tools/${path.basename(__filename)} --packmap"`);
		console.log(`const packmap = {`);
		console.log(codes.join('\n'));
		console.log(`};`);
	}

	if (runmode.binary) {
		var buffer = '';
		data.forEach((d, cp) => {
			var dd = 0;
			for (var i = 0, mask = 1, goal = Object.keys(packmap).length; i <= goal; i++, mask <<= 1) {
				if (d & mask) {
					dd |= packmap[`${i}_`];
				}
			}
			buffer += String.fromCharCode((cp      ) & 0xff);
			buffer += String.fromCharCode((cp >>  8) & 0xff);
			buffer += String.fromCharCode((dd      ) & 0xff);
			buffer += String.fromCharCode((dd >>  8) & 0xff);
			buffer += String.fromCharCode((dd >> 16) & 0xff);
		});

		fs.writeFileSync(out_file, buffer, {encoding:'binary', mode:0o664});
		console.log(`\ndone.`);
	}
}

function printHelp () {
	console.log('runmode not specified. set one of the following switches:');
	console.log('  --packmap  Output javascript code which defines packmap to stdout');
	console.log('  --binary   Output data file to src/chrome/unicode/fftt_han_ja.dat');
	process.exit(1);
}

(new OptionParser)
	.on('--packmap  Output javascript code which defines packmap to stdout', v => {
		runmode.packmap = true;
	})
	.on('--binary   Output data file to src/chrome/unicode/fftt_han_ja.dat', v => {
		runmode.binary = true;
	})
	.parse(process.argv);

getVersion()
.then(ver => version = ver)
.then(() => {
	if (!runmode.packmap && !runmode.binary) {
		printHelp();
	}
	else {
		setup();
		make_dict();
	}
})
.catch(error => console.error(error));

